/**
 * Copyright (C) 2011 KingCore Science & Technology CO,.LTD. All rights reserved.
 * XNS PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */

/**
 * Copyright (C) 2002-2011 WUZEWEN. All rights reserved.
 * WUZEWEN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 * This software is the confidential and proprietary information of
 * WuZeven, Personal. ("Confidential Information").  You shall not
 * disclose such Confidential Information and shall use it only in
 * accordance with the terms of the license agreement you entered into
 * with WuZeven.
 */

package wzw.swing.table;

import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Vector;

import javax.swing.Icon;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumnModel;

import wzw.beans.CodeNameBean;
import wzw.beans.TolerantNumberComparator;

/**
 * <p>java class file describe
 * 
 *    > 可编辑的JTable
 *    > 可排序的JTable
 *     wzw: change filed TableModel to DefaultTableModel.
 *    </p>
 * @author Zeven on 2011-2-24
 * @version	1.0
 * @see		Object#equals(java.lang.Object)
 * @since	JDK5
 */

public class PlainTableModel extends AbstractTableModel {
    /**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	protected DefaultTableModel tableModel;

    public static final int DESCENDING = -1;
    public static final int NOT_SORTED = 0;
    public static final int ASCENDING = 1;

    private static Directive EMPTY_DIRECTIVE = new Directive(-1, NOT_SORTED);

    
    public static void main(String[] args) {
	}
    
    /* *********************** Table Sort begin ******************************* */
    public static final Comparator<Object> COMPARABLE_COMAPRATOR = new Comparator<Object>() {
        public int compare(Object o1, Object o2) {
    		if ( o1==null ) {
    			if ( o2==null ) {
    				return 0;
    			}else{
    				return -1;
    			}
    		}else if( o2==null ){
    			return 1;
    		}
            return ((Comparable) o1).compareTo(o2);
        }
    };
    public static final Comparator LEXICAL_COMPARATOR = new Comparator() {
        public int compare(Object o1, Object o2) {
    		if ( o1==null ) {
    			if ( o2==null ) {
    				return 0;
    			}else{
    				return -1;
    			}
    		}else if( o2==null ){
    			return 1;
    		}
            return o1.toString().compareTo(o2.toString());
        }
    };

    private Row[] viewToModel;
    private int[] modelToView;

    private JTableHeader tableHeader;
    private MouseListener mouseListener;
    private TableModelListener tableModelListener;
    private Map<Class, Comparator<Object>> columnComparators = new HashMap<Class, Comparator<Object>>();
    private List sortingColumns = new ArrayList();

    public PlainTableModel() {
        this.mouseListener = new MouseHandler();
        this.tableModelListener = new TableModelHandler();

        columnComparators.put(java.lang.Integer.class, new TolerantNumberComparator(java.lang.Integer.class));
        columnComparators.put(java.lang.Long.class, new TolerantNumberComparator(java.lang.Long.class));
        columnComparators.put(CodeNameBean.class, new Comparator<Object>(){
			@Override
			public int compare(Object o1, Object o2) {
				if(o1==null){
					if (o2==null) {
						return 0;
					} else {
						return -1;
					}
				}
				if (o2==null) {
					return 1;
				}
				return ((CodeNameBean)o1).getCode().compareTo(((CodeNameBean)o2).getCode());
			}
        	
        });
        
//        // comparators add by wzw.
//        columnComparators.put(java.lang.Integer.class, new Comparator<Object>(){
//
//			public int compare(Object obj1, Object obj2) {
//				if (obj1==null) {
//					if (obj2==null) {
//						return 0;
//					}else{
//						return -1;
//					}
//				}
//				
//				Integer int1, int2;
//				try {
//					int1 = Integer.parseInt(obj1.toString());
//				} catch (Exception e) {
//					int1 = Integer.parseInt( ComponentUtil.filterUnNumber(obj1.toString()));
//				}
//				try {
//					int2 = Integer.parseInt(obj2.toString());
//				} catch (Exception e) {
//					int2 = Integer.parseInt( ComponentUtil.filterUnNumber(obj2.toString()));
//				}
//				return int1-int2;
//			}
//        });
//        columnComparators.put(java.lang.Long.class, new Comparator<Object>(){
//
//			public int compare(Object obj1, Object obj2) {
//				if (obj1==null) {
//					if (obj2==null) {
//						return 0;
//					}else{
//						return -1;
//					}
//				}
//				
//				Long int1, int2;
//				try {
//					int1 = Long.parseLong(obj1.toString());
//				} catch (Exception e) {
//					int1 = Long.parseLong( ComponentUtil.filterUnNumber(obj1.toString()));
//				}
//				try {
//					int2 = Long.parseLong(obj2.toString());
//				} catch (Exception e) {
//					int2 = Long.parseLong( ComponentUtil.filterUnNumber(obj2.toString()));
//				}
//				return (int) (int1-int2);
//			}
//        });
        
    }

    public PlainTableModel(DefaultTableModel tableModel) {
        this();
        setTableModel(tableModel);
    }

    public PlainTableModel(DefaultTableModel tableModel, JTableHeader tableHeader) {
        this();
        setTableHeader(tableHeader);
        setTableModel(tableModel);
    }

    public void clearSortingState() {
        viewToModel = null;
        modelToView = null;
    }

    public DefaultTableModel getTableModel() {
        return tableModel;
    }

    public void setTableModel(DefaultTableModel tableModel) {
        if (this.tableModel != null) {
            this.tableModel.removeTableModelListener(tableModelListener);
        }

        this.tableModel = tableModel;
        if (this.tableModel != null) {
            this.tableModel.addTableModelListener(tableModelListener);
        }

        clearSortingState();
        fireTableStructureChanged();
    }

    public JTableHeader getTableHeader() {
        return tableHeader;
    }

    public void setTableHeader(JTableHeader tableHeader) {
        if (this.tableHeader != null) {
            this.tableHeader.removeMouseListener(mouseListener);
            TableCellRenderer defaultRenderer = this.tableHeader.getDefaultRenderer();
            if (defaultRenderer instanceof SortableHeaderRenderer) {
                this.tableHeader.setDefaultRenderer(((SortableHeaderRenderer) defaultRenderer).tableCellRenderer);
            }
        }
        this.tableHeader = tableHeader;
        if (this.tableHeader != null) {
            this.tableHeader.addMouseListener(mouseListener);
            this.tableHeader.setDefaultRenderer(
                    new SortableHeaderRenderer(this.tableHeader.getDefaultRenderer()));
        }
    }

    public boolean isSorting() {
        return sortingColumns.size() != 0;
    }

    private Directive getDirective(int column) {
        for (int i = 0; i < sortingColumns.size(); i++) {
            Directive directive = (Directive)sortingColumns.get(i);
            if (directive.column == column) {
                return directive;
            }
        }
        return EMPTY_DIRECTIVE;
    }

    public int getSortingStatus(int column) {
        return getDirective(column).direction;
    }

    private void sortingStatusChanged() {
        clearSortingState();
        fireTableDataChanged();
        if (tableHeader != null) {
            tableHeader.repaint();
        }
    }

    private int currentSortColumnIndex = -1;
    public int getCurrentSortColumnIndex() {
		return currentSortColumnIndex;
	}

	public void setSortingStatus(int column, int status) {
        Directive directive = getDirective(column);
        if (directive != EMPTY_DIRECTIVE) {
            sortingColumns.remove(directive);
        }
        if (status != NOT_SORTED) {
            sortingColumns.add(new Directive(column, status));
            currentSortColumnIndex = column;
        }else{
            currentSortColumnIndex = -1;
        }
        sortingStatusChanged();
    }

    public void setSortingStatus(int column, int status, boolean sortInnerData) {
    	if (sortInnerData == false) {
    		setSortingStatus(column, status);
    		return;
		}
    	
    	//setSortingStatus(column, status);
    	int rcnt = this.getRowCount();
    	int pos = 0 ;
    	Object val = "";
    	Comparator<Object> comparator = getComparator(column);
    	for (int i = 0; i < rcnt; i++) {  //简单的1.5倍遍历排序算法，可以优化的排序算法
    		val = null;
    		pos = -1;
    		//find the biggest
    		for (int j = i; j < rcnt; j++) {
    			Object tmpVal = this.tableModel.getValueAt(j, column);
    			if (tmpVal==null) {
					continue;
				}
    			int cmpVal = comparator.compare(val, tmpVal);
    			if ( (status==0 && cmpVal==0)
    					|| (status*cmpVal)>0
//    					|| status>0 && cmpVal>0 
//    					|| status<0 && cmpVal<0 
    											) { //status:-1,0,1
    				val = tmpVal;
    				pos = j ;
				}
			}
    		//move biggest one to i
    		if (pos>-1) {
    			this.tableModel.moveRow(pos, pos, i); // move to the end of all matched.
    			// this.moveRow(pos, pos, i);   // ***not this one.
			}
		}
    }
    
    protected Icon getHeaderRendererIcon(int column, int size) {
        Directive directive = getDirective(column);
        if (directive == EMPTY_DIRECTIVE) {
            return null;
        }
        return new Arrow(directive.direction == DESCENDING, size, sortingColumns.indexOf(directive));
    }

    /**
     * 
     * <p>changed private to public.</p>
     * @author Zeven on 2011-3-10
     */
    public void cancelSorting() {
        sortingColumns.clear();
        currentSortColumnIndex = -1;
        sortingStatusChanged();
    }

    public void setColumnComparator(Class type, Comparator comparator) {
        if (comparator == null) {
            columnComparators.remove(type);
        } else {
            columnComparators.put(type, comparator);
        }
    }

    protected Comparator<Object> getComparator(int column) {
        Class<Object> columnType = getColumnClass(column);  //tableModel.
//        System.out.println(column+"---------"+columnType.getName().toString());
        Comparator<Object> comparator = (Comparator<Object>) columnComparators.get(columnType);
        if (comparator != null) {
            return comparator;
        }
        if (Comparable.class.isAssignableFrom(columnType)) {
            return COMPARABLE_COMAPRATOR;
        }
        return LEXICAL_COMPARATOR;
    }

    private Row[] getViewToModel() {
        if (viewToModel == null) {
            int tableModelRowCount = tableModel.getRowCount();
            viewToModel = new Row[tableModelRowCount];
            for (int row = 0; row < tableModelRowCount; row++) {
                viewToModel[row] = new Row(row);
            }

            if (isSorting()) {
                Arrays.sort(viewToModel);
            }
        }
        return viewToModel;
    }

    public int modelIndex(int viewIndex) {
    	int intVal = 0;
    	try {
    		intVal= getViewToModel()[viewIndex].modelIndex;
			
		} catch (Exception e) {
			e.printStackTrace();
			
		} finally {
		}
		return  intVal;
    }

    private int[] getModelToView() {
        if (modelToView == null) {
            int n = getViewToModel().length;
            modelToView = new int[n];
            for (int i = 0; i < n; i++) {
                modelToView[modelIndex(i)] = i;
            }
        }
        return modelToView;
    }


    public int getRowCount() {
        return (tableModel == null) ? 0 : tableModel.getRowCount();
    }

    public int getColumnCount() {
        return (tableModel == null) ? 0 : tableModel.getColumnCount();
    }

    public String getColumnName(int column) {
        return tableModel.getColumnName(column);
    }

    public Class<Object> getColumnClass(int column) {
        //return tableModel.getColumnClass(column);
    	if (coumnClassTypeMap.get(column)==null) {
			return java.lang.Object.class;  //Object.class
		}else{
			return coumnClassTypeMap.get(column);
		}
    }
    // add by wzw:
    private Map<Integer, Class> coumnClassTypeMap = new HashMap<Integer, Class>();
    public void setColumnClass(int colunm,Class clazz){
    	coumnClassTypeMap.put(colunm, clazz);
    }
    
//    public boolean isCellEditable(int row, int column) {
//        return tableModel.isCellEditable(modelIndex(row), column);
//    }

    public Object getValueAt(int row, int column) {
        return tableModel.getValueAt(modelIndex(row), column);
    }

    public void setValueAt(Object aValue, int row, int column) {
        tableModel.setValueAt(aValue, modelIndex(row), column);
    }

    /**
     * <p>java method describe</p>
     * @author Zeven on 2008-4-19
     * @param start
     * @param end
     * @param to
     */
    public void moveRow(int start, int end, int to){
        if(tableModel != null){
        	//tableModel.moveRow( start, end, to);
        	tableModel.moveRow( modelIndex(start), modelIndex(end), modelIndex(to));
        }
    }

    public void removeRow(int rowNum){
    	tableModel.removeRow(modelIndex(rowNum));
    }
    
	private class Row implements Comparable {
		private int modelIndex;

		public Row(int index) {
			this.modelIndex = index;
		}

		public int compareTo(Object o) {
			int retInt = 0;
			int row1 = modelIndex;
			int row2 = ((Row) o).modelIndex;
			for (Iterator it = sortingColumns.iterator(); it.hasNext();) {
				Directive directive = (Directive) it.next();
				int column = directive.column;
				Object o1 = tableModel.getValueAt(row1, column);
				Object o2 = tableModel.getValueAt(row2, column);
				int comparison = 0;
				if (o1 == null && o2 == null) {
					comparison = 0;
				} else if (o1 == null) {
					comparison = -1;
				} else if (o2 == null) {
					comparison = 1;
				} else {
					comparison = getComparator(column).compare(o1, o2);
				}
				if (comparison != 0) {
					retInt = directive.direction == DESCENDING ? -comparison
							: comparison;
				}
			}
			//System.out.println("compareTo = 0");
			return retInt;
		}
	}

	private boolean startTableModelListener = true;
	
	private class TableModelHandler implements TableModelListener {
		public void tableChanged(TableModelEvent e) {
			if ( startTableModelListener == false ) {
				System.out.println("-----------------return");
				return ;
			};
			//System.out.println("-----------------");
			if (!isSorting()) {
				clearSortingState();
				fireTableChanged(e);
				return;
			}
			if (e.getFirstRow() == TableModelEvent.HEADER_ROW) {
				cancelSorting();
				fireTableChanged(e);
				return;
			}
			int column = e.getColumn();
			if (e.getFirstRow() == e.getLastRow()
					&& column != TableModelEvent.ALL_COLUMNS
					&& getSortingStatus(column) == NOT_SORTED
					&& modelToView != null) {
				int viewIndex = getModelToView()[e.getFirstRow()];
				fireTableChanged(new TableModelEvent(PlainTableModel.this,
						viewIndex, viewIndex, column, e.getType()));
				return;
			}
			clearSortingState();
			fireTableDataChanged();
			return;
		}
	}

	private class MouseHandler extends MouseAdapter {
		public void mouseClicked(MouseEvent e) {
			JTableHeader h = (JTableHeader) e.getSource();
			TableColumnModel columnModel = h.getColumnModel();
			int viewColumn = columnModel.getColumnIndexAtX(e.getX());
			int column = columnModel.getColumn(viewColumn).getModelIndex();
			if (column != -1) {
				int status = getSortingStatus(column);
				if (!e.isControlDown()) {
					cancelSorting();
				}
				status = status + (e.isShiftDown() ? -1 : 1);
				status = (status + 4) % 3 - 1;
				setSortingStatus(column, status);
			}
		}
	}

	private static class Arrow implements Icon {
		private boolean descending;
		private int size;
		private int priority;

		public Arrow(boolean descending, int size, int priority) {
			this.descending = descending;
			this.size = size;
			this.priority = priority;
		}

		public void paintIcon(Component c, Graphics g, int x, int y) {
			Color color = c == null ? Color.GRAY : c.getBackground();
			int dx = (int) (size / 2 * Math.pow(0.8, priority));
			int dy = descending ? dx : -dx;
			y = y + 5 * size / 6 + (descending ? -dy : 0);
			int shift = descending ? 1 : -1;
			g.translate(x, y);
			g.setColor(color.darker());
			g.drawLine(dx / 2, dy, 0, 0);
			g.drawLine(dx / 2, dy + shift, 0, shift);
			g.setColor(color.brighter());
			g.drawLine(dx / 2, dy, dx, 0);
			g.drawLine(dx / 2, dy + shift, dx, shift);
			if (descending) {
				g.setColor(color.darker().darker());
			} else {
				g.setColor(color.brighter().brighter());
			}
			g.drawLine(dx, 0, 0, 0);
			g.setColor(color);
			g.translate(-x, -y);
		}

		public int getIconWidth() {
			return size;
		}

		public int getIconHeight() {
			return size;
		}
	}

	private class SortableHeaderRenderer implements TableCellRenderer {
		private TableCellRenderer tableCellRenderer;

		public SortableHeaderRenderer(TableCellRenderer tableCellRenderer) {
			this.tableCellRenderer = tableCellRenderer;
		}

		public Component getTableCellRendererComponent(JTable table,
				Object value, boolean isSelected, boolean hasFocus, int row,
				int column) {
			Component c = tableCellRenderer.getTableCellRendererComponent(
					table, value, isSelected, hasFocus, row, column);
			if (c instanceof JLabel) {
				JLabel l = (JLabel) c;
				l.setHorizontalTextPosition(JLabel.LEFT);
				int modelColumn = table.convertColumnIndexToModel(column);
				l.setIcon(getHeaderRendererIcon(modelColumn, l.getFont()
						.getSize()));
			}
			return c;
		}
	}

	private static class Directive {
		private int column;
		private int direction;

		public Directive(int column, int direction) {
			this.column = column;
			this.direction = direction;
		}
	}

	public boolean isStartTableModelListener() {
		return startTableModelListener;
	}

	public void setStartTableModelListener(boolean startTableModelListener) {
		this.startTableModelListener = startTableModelListener;
	}

	/*
	 * ---------------------------------- add by wzw ----------- begin
	 */
	Map<Integer,Integer> editableColumnsMap = new HashMap<Integer,Integer>();
	public void setColumnEditable(int colIndex){
		setColumnEditable(colIndex, true);
	}
	public void setColumnEditable(int colIndex, Boolean enable){
		if (enable) {
			editableColumnsMap.put(colIndex, 1);
		}else{
			editableColumnsMap.remove(colIndex);
		}
	}
	public boolean isCellEditable(int row,int col) {
		if (editableColumnsMap.get(col)!=null) {
			return true;
		}
		return false;
	}

	public void removeAllRows() {  //JTable table
		int row = this.getTableModel().getRowCount();
		for (int i = 0; i < row; i++) {  //remove all rows.
			this.getTableModel().removeRow(0);
		}
	}
	
	public void setData(Object[][] data) {  //JTable table
		removeAllRows();
		for (int i = 0; i < data.length; i++) {
			this.getTableModel().addRow(data[i]);
		}
		
	}
	public void setData(List<Vector> data) {  //JTable table
		removeAllRows();
		for (int i = 0; i < data.size(); i++) {
			this.getTableModel().addRow(data.get(i));
		}
		
	}
	
	/*
	 * ---------------------------------- add by wzw ----------- end1
	 */
	
}
